/**
 * Copyright (C) 2011 dan.zheng <cmaj135@gmail.com>
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *         http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package org.krosa.net.http.impl;

import java.io.BufferedReader;
import java.io.DataOutputStream;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.net.HttpURLConnection;
import java.net.URL;

import javax.net.ssl.HttpsURLConnection;
import javax.net.ssl.SSLContext;
import javax.net.ssl.SSLSocketFactory;

import org.apache.commons.io.IOUtils;
import org.apache.commons.lang.StringUtils;
import org.krosa.net.http.Client;
import org.krosa.net.http.entity.Response;
import org.krosa.net.http.exception.KrosaException;
import org.krosa.net.http.util.CharsetUtil;

/**
 * <p>
 * the basic http client to retrieve data from Web Server
 * </p>
 * 
 * @author dan.zheng Email:cmaj135@gmail.com.
 * @version
 * <p>
 * create date: Jun 28, 2011 2:25:16 PM.
 * </p>
 */
public class BasicHttpClient implements Client {
    /**/
    private boolean isSSLSupport;

    public BasicHttpClient() {
        // do nothing
    }

    public BasicHttpClient(boolean isSSLSupport) {
        this.isSSLSupport = isSSLSupport;
    }

    public Response get(String url) throws KrosaException {
        Response r = new Response();
        try {
            URL getUrl = new URL(url);
            HttpURLConnection connection = null;
            if (isSSLSupport) {
                connection = (HttpsURLConnection) getUrl.openConnection();
                SSLContext sslContext = ImplicityCustomSSL.createImplicitySSLContext();
                SSLSocketFactory ssf = sslContext.getSocketFactory();
                ((HttpsURLConnection) connection).setSSLSocketFactory(ssf);
            } else
                connection = (HttpURLConnection) getUrl.openConnection();
            connection.setInstanceFollowRedirects(true);
            long l1 = System.currentTimeMillis();
            connection.connect();
            long l2 = System.currentTimeMillis();
            r.setConnServerTime(l2 - l1);
            // use reader to receive the page data
            long l3 = System.currentTimeMillis();
            InputStream is = connection.getInputStream();
            byte[] content = IOUtils.toByteArray(is);
            long l4 = System.currentTimeMillis();
            long len = content.length;
            r.setDownSpeed((double) (l4 - l1) / len);
            r.setServerResponseTime(l3 - l2);
            String charset = CharsetUtil.getCharSet(content);
            r.setCharSet(charset);
            r.setContent(new String(content,charset));
            is.close();
            connection.disconnect();
        } catch (Exception e) {
            throw new KrosaException("", e);
        }
        return r;
    }

    public Response post(String url, String postData) throws KrosaException {
        Response r = new Response();
        try {
            URL postUrl = new URL(url);

            HttpURLConnection connection = (HttpURLConnection) postUrl.openConnection();
            // Output to the connection. Default is
            // false, set to true because post
            // method must write something to the
            // connection
            connection.setDoOutput(true);
            // Read from the connection. Default is true.
            connection.setDoInput(true);
            // Set the post method. Default is GET
            connection.setRequestMethod("POST");
            // Post cannot use caches
            connection.setUseCaches(false);
            // This method takes effects to
            // every instances of this class.
            connection.setInstanceFollowRedirects(true);
            // Set the content type to urlencoded,
            // because we will write
            // some URL-encoded content to the
            // connection. Settings above must be set before connect!
            connection.setRequestProperty("Content-Type", "application/x-www-form-urlencoded");

            long l1 = System.currentTimeMillis();
            connection.connect();
            long l2 = System.currentTimeMillis();
            r.setConnServerTime(l2 - l1);
            if (!StringUtils.isBlank(postData)) {
                DataOutputStream out = new DataOutputStream(connection.getOutputStream());
                out.writeBytes(postData);
                out.flush();
                out.close(); // flush and close
            }
            BufferedReader reader = new BufferedReader(new InputStreamReader(connection.getInputStream()));
            long l3 = System.currentTimeMillis();
            String content = IOUtils.toString(reader);
            long l4 = System.currentTimeMillis();
            long len = content.getBytes().length;
            r.setDownSpeed((double) (l4 - l1) / len);
            r.setServerResponseTime(l3 - l2);
            r.setCharSet(CharsetUtil.getCharSet(content));
            r.setContent(content);
            reader.close();
            connection.disconnect();
        } catch (Exception e) {
            throw new KrosaException("", e);
        }
        return r;
    }
}
